﻿//-----------------------------------------------------------------------
// <copyright file="Copyright.cs" author="Michael Herndon">
//     Copyright (c) Michael Herndon.  All rights reserved.
// </copyright>
//-----------------------------------------------------------------------

namespace Amplify.Twitter
{
	using System;
	using System.Collections.Generic;
	using System.IO; 
	using System.Linq;
	using System.Net;
	using System.Reflection;
	using System.Runtime.Serialization;
	using System.Runtime.Serialization.Json;
	using System.ServiceModel;
	using System.ServiceModel.Channels;
	using System.ServiceModel.Description;
	using System.ServiceModel.Security;
	using System.ServiceModel.Web;
	using System.Text;


	/// <summary>
	/// The base class for twitter rest clients. 
	/// </summary>
	/// <typeparam name="T">The interfaced Client contract.</typeparam>
	public class TwitterClient<T> 
	{


		/// <summary>
		/// Initializes a new instance of the <see cref="TwitterClient&lt;T&gt;"/> class.
		/// </summary>
		public TwitterClient()
		{
			this.Url = "https://twitter.com";
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="TwitterClient&lt;T&gt;"/> class.
		/// </summary>
		/// <param name="username">The username.</param>
		/// <param name="password">The password.</param>
		public TwitterClient(string username, string password)
			: this()
		{
			this.Username = username;
			this.Proxy = this.InitializeProxy(username, password);
		}


		/// <summary>
		/// Gets or sets the proxy.
		/// </summary>
		/// <value>The proxy.</value>
		protected T Proxy { get; set; }

		/// <summary>
		/// Gets or sets the URL.
		/// </summary>
		/// <value>The URL.</value>
		protected string Url { get; set; }

		/// <summary>
		/// Gets or sets the username.
		/// </summary>
		/// <value>The username.</value>
		protected string Username { get; set; }


		/// <summary>
		/// Rescues the specified security exception.
		/// </summary>
		/// <param name="securityException">The security exception.</param>
		protected void Rescue(MessageSecurityException securityException)
		{

			if (securityException != null && securityException.InnerException != null)
			{
				WebException webException = securityException.InnerException as WebException;

				if (webException != null && webException.Response != null)
				{
					HttpWebResponse response = webException.Response as HttpWebResponse;
					using(Stream stream = response.GetResponseStream()) 
					{
						string output = "";
						using (StreamReader sr = new StreamReader(stream))
						{
							output = sr.ReadToEnd();
						
							stream.Position = 0;
							TwitterError obj = null;
							if (output.Contains("<hash>"))
							{
								DataContractSerializer serializer = new DataContractSerializer(typeof(TwitterError));
								obj = (TwitterError)serializer.ReadObject(stream);
								throw new TwitterException(obj.Error, response.StatusCode, response.ResponseUri.ToString());
							}
							else
							{
								DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(TwitterError));
								obj = (TwitterError)serializer.ReadObject(stream);
								throw new TwitterException(obj.Error, response.StatusCode, response.ResponseUri.ToString());
							}
						}
					}
				}

			}
			throw securityException;
		}

		/// <summary>
		/// Initializes the proxy.
		/// </summary>
		/// <param name="username">The username.</param>
		/// <param name="password">The password.</param>
		/// <returns>returns an object of type T.</returns>
		protected virtual T InitializeProxy(string username, string password)
		{
			CustomBinding binding = new CustomBinding();

			
			

			
			binding.Elements.Add(new WebMessageEncodingBindingElement());

			binding.Elements.Add(new HttpsTransportBindingElement()
			{
				ManualAddressing = true,
				AuthenticationScheme = System.Net.AuthenticationSchemes.Basic
			}); // must be the last element to be added. so says almighty WCF. 

		
			ChannelFactory<T> channel = new ChannelFactory<T>(
				binding, this.Url);

			channel.Endpoint.Behaviors.Add(new WebHttpBehavior());
			channel.Credentials.UserName.UserName = username;
			channel.Credentials.UserName.Password = password;

			return channel.CreateChannel();
		}

	}
}
